package com.p2l.letterblocks;

import java.util.Calendar;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class GameView extends SurfaceView implements Runnable {
	private static final int FPS = 1000 / 60;
	public static final int BOTTOM = 3;
	public static float GAME_MULTIPLIER = 0.5f;
	public static int GAME_WIDTH = (int)(GamePersistor.SCREEN_WIDTH / GAME_MULTIPLIER);
	
	private GamePersistor persistor;
	private SurfaceHolder holder;
	private Thread t = null;
	private Bitmap background, background_layer, floor;
	private Rect bRect, fRect, bounds;
	private Paint p;

	private String loading;
	private float padding;
	private long time, timeStarted;

	public boolean running = false;
	
	public GameView(Context context) {
		super(context);
		persistor = (GamePersistor) context;
	}
	
	public GameView(Context context, AttributeSet attrs) {
		super(context, attrs);
		persistor = (GamePersistor) context;
	}
	
	public GameView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		persistor = (GamePersistor) context;
	}
	
	@Override
	protected void onFinishInflate() {
		holder = getHolder();
		time = Calendar.getInstance().getTimeInMillis();
		
		bRect = new Rect(0, 0, GamePersistor.SCREEN_WIDTH, GamePersistor.SCREEN_HEIGHT);
		fRect = new Rect(0, (int)(GamePersistor.SCREEN_HEIGHT / 100f * (100 - BOTTOM)), GamePersistor.SCREEN_WIDTH, GamePersistor.SCREEN_HEIGHT);
		
		loading = persistor.getResources().getString(R.string.label_loading);
		padding = persistor.getResources().getDimension(R.dimen.padding_small);
		
		timeStarted = Calendar.getInstance().getTimeInMillis();
		bounds = new Rect();
		p = new Paint();
		p.setColor(Color.WHITE);
		p.setTypeface(Typeface.DEFAULT_BOLD);
		p.setTextSize(persistor.getResources().getDimension(R.dimen.text_normal));
		p.getTextBounds(loading, 0, loading.length(), bounds);
	}

	@Override
	public void run() {
		while (running) {
			if (!holder.getSurface().isValid()) {
				continue;
			}
			
			// lock canvas to draw
			Canvas c = holder.lockCanvas();
			
			long timeEnd = Calendar.getInstance().getTimeInMillis();
			int elapsed = (int)(timeEnd - time);
			if (elapsed < FPS) {
				try {
					Thread.sleep(FPS - elapsed);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			timeEnd = Calendar.getInstance().getTimeInMillis();
			elapsed = (int)(timeEnd - time);
			if (elapsed > 30)
				elapsed = 30;
			time = timeEnd;
			long currentTime = Calendar.getInstance().getTimeInMillis();
			
			// if loading
			if (persistor.loading || currentTime - timeStarted < 2500) {
				c.drawBitmap(persistor.getModel().getLoading(), null, bRect, null);
				c.drawText(loading, GamePersistor.SCREEN_WIDTH - bounds.width() - padding, GamePersistor.SCREEN_HEIGHT - padding, p);
			} else {
				// objects to be drawn
				Bear bear = persistor.getModel().getBear();
				if (bear != null) {
					// check if bear should be centered on the screen
					float camera = bear.getX() + (bear.getWidth() / 2);
					if (camera > GAME_WIDTH - (GamePersistor.SCREEN_WIDTH / 2))
						camera -= GAME_WIDTH - GamePersistor.SCREEN_WIDTH;
					else if (camera > GamePersistor.SCREEN_WIDTH / 2)
						camera = GamePersistor.SCREEN_WIDTH / 2;
					
					// find where on the screen the blocks and obstacles should be drawn
					float object = 0f;
					if (bear.getX() + (bear.getWidth() / 2) > GAME_WIDTH - (GamePersistor.SCREEN_WIDTH / 2))
						object = GAME_WIDTH - GamePersistor.SCREEN_WIDTH;
					else if (bear.getX() + (bear.getWidth() / 2) > GamePersistor.SCREEN_WIDTH / 2)
						object = bear.getX() - (GamePersistor.SCREEN_WIDTH / 2) + (bear.getWidth() / 2);
					
					// ms since last update
					int delta = persistor.delta();
					
					// draw background
					c.drawBitmap(background, null, bRect, null);
		
					float percent = object / GamePersistor.SCREEN_WIDTH;
					float left = (background_layer.getWidth() / 3 * percent);
					float right = ((background_layer.getWidth() * percent / 3) + (background_layer.getWidth() / 3 * 2));
					Rect r = new Rect((int)left, 0, (int)right, background_layer.getHeight());
					c.drawBitmap(background_layer, r, bRect, null);
		
					left = (floor.getWidth() * percent / 2);
					right = ((floor.getWidth() * percent / 2) + (floor.getWidth() / 2));
					r = new Rect((int)left, 0, (int)right, floor.getHeight());
					c.drawBitmap(floor, r, fRect, null);
					
					// draw the letter blocks
					for (int i = 0; i < persistor.getModel().getBlocks().length; i++) {
						// make sure the block the bear is holding isn't jumping forward and backwards when the bear is moving
						if (persistor.getModel().getBlocks()[i].getX() + persistor.getModel().getBlocks()[i].getWidth() >= object && persistor.getModel().getBlocks()[i].getX() <= object + GamePersistor.SCREEN_WIDTH) {
							if (bear.getBlock() == persistor.getModel().getBlocks()[i] && camera == GamePersistor.SCREEN_WIDTH / 2)
								persistor.getModel().getBlocks()[i].onDraw(c, delta, bear.getX() - (GamePersistor.SCREEN_WIDTH / 2) + (bear.getBlock().getWidth() / 2));
							else
								persistor.getModel().getBlocks()[i].onDraw(c, delta, object);
						}
					}
					
					// draw the obstacles
					for (int i = 0; i < persistor.getModel().getObstacles().length; i++)
						if (persistor.getModel().getObstacles()[i].getX() + persistor.getModel().getObstacles()[i].getWidth() >= object && persistor.getModel().getObstacles()[i].getX() <= object + GamePersistor.SCREEN_WIDTH)
							persistor.getModel().getObstacles()[i].onDraw(c, delta, object);
					
					// draw the bear
					bear.onDraw(c, (persistor.getModel().getPause().isPaused() ? -1 : (persistor.getModel().getEndLevel().isFinished() ? -1 : delta)), camera);
					
					// draw coin
					if (persistor.getModel().getCoin() != null)
						if (!persistor.getModel().getCoin().isCollected())
							if (persistor.getModel().getCoin().getX() + persistor.getModel().getCoin().getWidth() >= object && persistor.getModel().getCoin().getX() <= object + GamePersistor.SCREEN_WIDTH)
								persistor.getModel().getCoin().onDraw(c, delta, object);
					
					// check if the 'letter block pick up'-button should be enabled
					boolean found = false;
					if (bear.getBlock() != null) {
						found = true;
					} else {
						int i = 0;
						while (!found && i < persistor.getModel().getBlocks().length) {
							if (bear.isColliding(persistor.getModel().getBlocks()[i])) {
								if (bear.getY() + bear.getHeight() > persistor.getModel().getBlocks()[i].getY() + GameModel.FACTOR && bear.getY() - GameModel.FACTOR < persistor.getModel().getBlocks()[i].getY() + persistor.getModel().getBlocks()[i].getHeight())
									found = true;
								else
									i++;
							} else
								i++;
						}
					}
					
					// draw and enable the button if found
					Button button = persistor.getModel().getPickButton();
					if (found) {
						button.setEnabled(true);
						button.onDraw(c, delta, camera);
					} else
						button.setEnabled(false);
				}
				
				EndLevel endLevel = persistor.getModel().getEndLevel();
				Pause pause = persistor.getModel().getPause();
				Button word = persistor.getModel().getWordButton();
				
				if(endLevel.isFinished()) {
					// draw endLevel
	 				endLevel.onDraw(c);
				} else if (pause.isPaused()) {
					// draw pause
					pause.onDraw(c);
				}
	
				// draw word button
				word.onDraw(c, 0, 0f);
			}
			
			// unlock and post the drawn canvas
			holder.unlockCanvasAndPost(c);
		}
	}
	
	public void setBackground(Bitmap bitmap) {
		background = bitmap;
	}
	
	public void setBackgroundLayer(Bitmap bitmap) {
		background_layer = bitmap;
	}
	
	public void setFloor(Bitmap bitmap) {
		floor = bitmap;
	}
	
	public void onPause() {
		running = false;
		while (true) {
			try {
				t.join();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			break;
		}
	}
	
	public void onResume() {
		running = true;
		t = new Thread(this);
		t.start();
		time = Calendar.getInstance().getTimeInMillis();
	}
	
	public void onDestroy() {
		background.recycle();
		background_layer.recycle();
		floor.recycle();
		
		background_layer = null;
		background = null;
		persistor = null;
		holder = null;
		floor = null;
		bRect = null;
		fRect = null;
		t = null;
	}
}